import 'package:flutter/material.dart';

import 'controller/cut_canvas_controller.dart';
import 'controller/cut_canvas_scalestate_controller.dart';
import 'core/cut_canvas_internal.dart';
import 'utils/adaptive_scale.dart';
import 'utils/hero_attributes.dart';

export 'controller/cut_canvas_controller.dart';
export 'controller/cut_canvas_scalestate_controller.dart';
export 'utils/adaptive_scale.dart';
export 'utils/hero_attributes.dart';

/// 基于[https://github.com/renancaraujo/photo_view]做了一定的修改和精简
/// 1. 自定义child Widget
/// 2. 设置最大，最小和默认缩放值
/// 3. controller处理模式
class CutCanvasWidget extends StatefulWidget {
  CutCanvasWidget({
    Key key,
    @required this.child,
    this.heroAttributes,
    this.scaleStateChangedCallback,
    this.enableRotation = false,
    this.controller,
    this.scaleStateController,
    this.maxScale,
    this.minScale,
    this.initialScale,
    this.basePosition,
    this.scaleStateCycle,
    this.onScaleEnd,
    this.tightMode,
  }) : super(key: key);

  final HeroAttributes heroAttributes;

  /// scaleState变更回调，当外部管理scaleStateController生命周期时，直接通过scaleStateController监听更好
  final ValueChanged<CanvasScaleState> scaleStateChangedCallback;

  /// 是否启用旋转手势
  final bool enableRotation;

  /// 自定义子控件内容
  final Widget child;

  /// 最大缩放值，只接收double或[AdaptiveScale]类型
  final dynamic maxScale;

  /// 最小缩放值，只接收double或[AdaptiveScale]类型
  final dynamic minScale;

  /// 默认缩放值，只接收double或[AdaptiveScale]类型
  final dynamic initialScale;

  /// 通过controller控制变换操作或监听内容变更
  final CutCanvasControllerBase controller;

  /// 只控制缩放状态的controller
  final CutCanvasScaleStateController scaleStateController;

  /// 缩放手势的中心点，默认[Alignment.center]，位置定位是相对于Widget的大小
  final Alignment basePosition;

  /// Defines de next [CanvasScaleState] given the actual one. Default is [defaultScaleStateCycle]
  final ScaleStateCycle scaleStateCycle;

  final CanvasScaleEndCallback onScaleEnd;

  /// Enables tight mode, making background container assume the size of the image/child.
  /// Useful when inside a [Dialog]
  final bool tightMode;

  @override
  State<StatefulWidget> createState() {
    return _CutCanvasWidgetState();
  }
}

class _CutCanvasWidgetState extends State<CutCanvasWidget> {
  bool _internalController;
  CutCanvasControllerBase _controller;

  bool _internalScaleStateController;
  CutCanvasScaleStateController _scaleStateController;

  @override
  void initState() {
    super.initState();
    if (widget.controller == null) {
      _internalController = true;
      _controller = CutCanvasController();
    } else {
      _internalController = false;
      _controller = widget.controller;
    }

    if (widget.scaleStateController == null) {
      _internalScaleStateController = true;
      _scaleStateController = CutCanvasScaleStateController();
    } else {
      _internalScaleStateController = false;
      _scaleStateController = widget.scaleStateController;
    }

    _scaleStateController.scaleStateStream.listen(scaleStateListener);
  }

  @override
  void didUpdateWidget(CutCanvasWidget oldWidget) {
    if (widget.controller == null) {
      if (!_internalController) {
        _internalController = true;
        _controller = CutCanvasController();
      }
    } else {
      _internalController = false;
      _controller = widget.controller;
    }

    if (widget.scaleStateController == null) {
      if (!_internalScaleStateController) {
        _internalScaleStateController = true;
        _scaleStateController = CutCanvasScaleStateController();
      }
    } else {
      _internalScaleStateController = false;
      _scaleStateController = widget.scaleStateController;
    }
    super.didUpdateWidget(oldWidget);
  }

  @override
  void dispose() {
    if (_internalController) {
      _controller.dispose();
    }
    if (_internalScaleStateController) {
      _scaleStateController.dispose();
    }
    super.dispose();
  }

  void scaleStateListener(CanvasScaleState scaleState) {
    widget.scaleStateChangedCallback?.call(_scaleStateController.scaleState);
  }

  @override
  Widget build(BuildContext context) {
    return LayoutBuilder(
      builder: (BuildContext context, BoxConstraints constraints) {
        return CutCanvasInternalWidget(
          child: widget.child,
          enableRotation: widget.enableRotation,
          heroAttributes: widget.heroAttributes,
          controller: _controller,
          scaleStateController: _scaleStateController,
          scaleStateCycle: widget.scaleStateCycle ?? defaultScaleStateCycle,
          basePosition: widget.basePosition ?? Alignment.center,
          onScaleEnd: widget.onScaleEnd,
        );
      },
    );
  }
}

/// The default [ScaleStateCycle]
CanvasScaleState defaultScaleStateCycle(CanvasScaleState actual) {
  switch (actual) {
    case CanvasScaleState.initial:
      return CanvasScaleState.covering;
    case CanvasScaleState.covering:
      return CanvasScaleState.originalSize;
    case CanvasScaleState.originalSize:
      return CanvasScaleState.initial;
    case CanvasScaleState.zoomedIn:
    case CanvasScaleState.zoomedOut:
      return CanvasScaleState.initial;
    default:
      return CanvasScaleState.initial;
  }
}

/// 双击周期状态变更回调处理
typedef ScaleStateCycle = CanvasScaleState Function(CanvasScaleState actual);

typedef CanvasScaleEndCallback = Function(
  double finalX,
  double finalY,
  double sacle,
);

enum CanvasScaleState {
  initial,
  covering,
  originalSize,
  zoomedIn,
  zoomedOut,
}

extension CanvasScaleStateIZoomingExtension on CanvasScaleState {
  bool get isScaleStateZooming =>
      this == CanvasScaleState.zoomedIn || this == CanvasScaleState.zoomedOut;
}
